#include <cmath>

#include <opencv2/core/mat.hpp>
#include <opencv2/core/types.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

static cv::Point2f
bezier3 (cv::Point2f const &p0, cv::Point2f const &p1, cv::Point2f const &p2,
         cv::Point2f const &p3, float t)
{
  float b0 = std::pow (1.0f - t, 3.0f);
  float b1 = 3.0f * t * std::pow (1.0f - t, 2.0f);
  float b2 = 3.0f * std::pow (t, 2.0) * (1.0f - t);
  float b3 = std::pow (t, 3.0f);

  float x = b0 * p0.x + b1 * p1.x + b2 * p2.x + b3 * p3.x;
  float y = b0 * p0.y + b1 * p1.y + b2 * p2.y + b3 * p3.y;

  return cv::Point2f (x, y);
}

int
main (void)
{
  int image_width = 480;
  int image_height = 320;

  cv::Mat image (cv::Size (image_width, image_height), CV_8UC3);

  cv::Point2f p0 (100, 100);
  cv::Point2f p1 (150, 50);
  cv::Point2f p2 (250, 250);
  cv::Point2f p3 (300, 100);

  std::vector<cv::Point> curve;
  for (float t = 0.0f; t <= 1.0f; t += 0.01f)
    {
      auto p = bezier3 (p0, p1, p2, p3, t);
      curve.push_back (p);
    }

  bool is_closed = false;
  int thickness = 2;
  cv::Scalar color_red (0, 0, 255);
  cv::polylines (image, curve, is_closed, color_red, thickness);

  const char *window_name = "opencv_test";

  cv::imshow (window_name, image);
  cv::waitKey (-1);

  cv::destroyAllWindows ();
  return 0;
}
